﻿package core.drawing
{
    import __AS3__.vec.*;
    import core.enum.*;
    import core.image.*;
    import flash.display.*;
    import flash.events.*;
    import flash.geom.*;

    final public class WandTool extends SelectionTool
    {
        var target:BitmapData;
        var offset:Point;
        var ranges:Vector.<Range>;
        var pxchecked:Vector.<Boolean>;
        var aa:Number;
        var diff:int;
        var max:int;
        var px:uint;
        var a:int;
        var r:int;
        var g:int;
        var b:int;
        var ta:int;
        var tr:int;
        var tg:int;
        var tb:int;

        public function WandTool(param1:Tuyitu)
        {
            super(param1, ToolType.Wand);
            return;
        }// end function

        override public function MouseDown(event:MouseEvent) : void
        {
            if (!type.attitude.locked)
            {
                this.UpdateReferences();
                if (type.attitude.method != "move")
                {
                    history.Prepare(Action.WandTool);
                    this.offset = canvas.layer.offset;
                    this.target = canvas.layer.bitmap.bitmapData;
                    options.deselect = Boolean(!event.shiftKey && event.ctrlKey);
                    po = canvas.GetOffsetMousePosition(this.offset);
                    if (selection == null)
                    {
                        canvas.AddSelection();
                        selection = canvas.selection;
                    }
                    else if (selection != null && !event.shiftKey && !event.ctrlKey)
                    {
                        selection.Reset();
                    }
                    if (po.x >= 0 && po.y >= 0 && po.x < this.target.width && po.y < this.target.height)
                    {
                        this.px = this.target.getPixel32(po.x, po.y);
                        this.ta = this.px >>> 24 & 255;
                        this.tr = this.px >>> 16 & 255;
                        this.tg = this.px >>> 8 & 255;
                        this.tb = this.px & 255;
                        if (!options.contiguous)
                        {
                            this.FillAll();
                        }
                        else
                        {
                            this.FloodFill(po.x, po.y);
                        }
                        selection.CreateOutline();
                    }
                    canvas.coating.Clear();
                    canvas.coating.Redraw();
                    if (selection != null && (selection.width == 0 || selection.height == 0))
                    {
                        canvas.RemoveSelection();
                    }
                    ed.navigator.SetSelectionSize(selection.width, selection.height);
                    history.Commit();
                }
                else
                {
                    this.SelectionDown();
                }
            }
            return;
        }// end function

        override public function Reset() : void
        {
            type.attitude.locked = Boolean(ed.canvas.layer.type != LayerType.Bitmap);
            if (AppState.OnCanvas)
            {
                ed.cursor.Set(type);
            }
            ed.options.SetTool(type);
            return;
        }// end function

        private function FillAll() : void
        {
            var _loc_1:int = 0;
            var _loc_2:int = 0;
            var _loc_3:int = 0;
            var _loc_4:int = 0;
            var _loc_5:* = this.target.height;
            while (_loc_4 < _loc_5)
            {
                
                _loc_2 = 0;
                _loc_3 = this.target.width;
                while (_loc_2 < _loc_3)
                {
                    
                    _loc_1 = this.Tolerate(_loc_2, _loc_4);
                    if (_loc_1 > 5)
                    {
                        selection.EditPoint(_loc_2 + this.offset.x, _loc_4 + this.offset.y, _loc_1, options.deselect);
                    }
                    _loc_2++;
                }
                _loc_4++;
            }
            return;
        }// end function

        private function FloodFill(tr:int, tr:int) : void
        {
            var _loc_3:Range = null;
            var _loc_4:int = 0;
            var _loc_5:* = this.target.width;
            var _loc_6:* = this.target.height;
            this.ranges = new Vector.<Range>;
            this.pxchecked = new Vector.<Boolean>(_loc_5 * _loc_6, true);
            this.LinearFill(tr, tr, this.Tolerate(tr, tr));
            while (this.ranges.length > 0)
            {
                
                _loc_3 = this.ranges.shift();
                _loc_4 = _loc_3.start;
                while (_loc_4 <= _loc_3.stop)
                {
                    
                    if (_loc_3.row > 0 && !this.pxchecked[(_loc_3.row - 1) * _loc_5 + _loc_4])
                    {
                        this.LinearFill(_loc_4, (_loc_3.row - 1), this.Tolerate(_loc_4, (_loc_3.row - 1)));
                    }
                    if (_loc_3.row < (_loc_6 - 1) && !this.pxchecked[(_loc_3.row + 1) * _loc_5 + _loc_4])
                    {
                        this.LinearFill(_loc_4, (_loc_3.row + 1), this.Tolerate(_loc_4, (_loc_3.row + 1)));
                    }
                    _loc_4++;
                }
            }
            return;
        }// end function

        private function LinearFill(tr:int, tr:int, tr:int) : void
        {
            var _loc_4:int = 0;
            var _loc_5:int = 0;
            var _loc_6:Range = null;
            var _loc_7:* = this.target.width;
            this.pxchecked[_loc_7 * tr + tr] = true;
            if (tr > 5)
            {
                selection.EditPoint(tr + this.offset.x, tr + this.offset.y, tr, options.deselect);
            }
            if (tr > 64)
            {
                _loc_4 = tr - 1;
                _loc_5 = tr + 1;
                while (_loc_4 >= 0 && !this.pxchecked[_loc_7 * tr + _loc_4] && tr > 64)
                {
                    
                    this.pxchecked[_loc_7 * tr + _loc_4] = true;
                    tr = this.Tolerate(_loc_4, tr);
                    if (tr > 5)
                    {
                        selection.EditPoint(_loc_4 + this.offset.x, tr + this.offset.y, tr, options.deselect);
                    }
                    _loc_4 = _loc_4 - 1;
                }
                tr = 255;
                while (_loc_5 < _loc_7 && !this.pxchecked[_loc_7 * tr + _loc_5] && tr > 64)
                {
                    
                    this.pxchecked[_loc_7 * tr + _loc_5] = true;
                    tr = this.Tolerate(_loc_5, tr);
                    if (tr > 5)
                    {
                        selection.EditPoint(_loc_5 + this.offset.x, tr + this.offset.y, tr, options.deselect);
                    }
                    _loc_5++;
                }
                _loc_6 = new Range((_loc_4 + 1), (_loc_5 - 1), tr);
                this.ranges.push(_loc_6);
            }
            return;
        }// end function

        private function Tolerate(OnCanvas:int, OnCanvas:int) : int
        {
            this.max = 0;
            this.px = this.target.getPixel32(OnCanvas, OnCanvas);
            this.a = this.px >>> 24 & 255;
            this.a = this.ta - this.a;
            this.diff = this.a < 0 ? (-this.a) : (this.a);
            if (this.diff > this.max)
            {
                this.max = this.diff;
            }
            if (this.ta > 0)
            {
                this.r = this.px >>> 16 & 255;
                this.g = this.px >>> 8 & 255;
                this.b = this.px & 255;
                this.r = this.tr - this.r;
                this.diff = this.r < 0 ? (-this.r) : (this.r);
                if (this.diff > this.max)
                {
                    this.max = this.diff;
                }
                this.g = this.tg - this.g;
                this.diff = this.g < 0 ? (-this.g) : (this.g);
                if (this.diff > this.max)
                {
                    this.max = this.diff;
                }
                this.b = this.tb - this.b;
                this.diff = this.b < 0 ? (-this.b) : (this.b);
                if (this.diff > this.max)
                {
                    this.max = this.diff;
                }
            }
            if (options.antialias && options.tolerance > 0)
            {
                this.aa = 1.5 - this.max / options.tolerance;
                if (this.aa <= 0)
                {
                    return 0;
                }
                if (this.aa < 0.5)
                {
                    return int(this.aa * 512);
                }
                return 255;
            }
            if (this.max > options.tolerance)
            {
                return 0;
            }
            return 255;
        }// end function

    }
}
